Lambdaでboto3を使ってDevice Shadowを取得しようとしたらSSLでエラーが起きたから応急処置をする
こんにちはCX事業本部の夏目です。
boto3でIoT CoreのDevice ShadowにアクセスしようとしたりするとSSLでエラーが発生する事象が起きています。
とりあえずその応急処置の方法を共有します。
発生しているエラー
{ "errorMessage": "SSL validation failed for https://data.iot.ap-northeast-1.amazonaws.com/things/test_device/shadow [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1091)", "errorType": "SSLError", "stackTrace": [ " File \"/var/task/lambda_function.py\", line 8, in lambda_handler\n resp = iot.get_thing_shadow(thingName='lip_t9999')\n", " File \"/var/runtime/botocore/client.py\", line 357, in _api_call\n return self._make_api_call(operation_name, kwargs)\n", " File \"/var/runtime/botocore/client.py\", line 663, in _make_api_call\n operation_model, request_dict, request_context)\n", " File \"/var/runtime/botocore/client.py\", line 682, in _make_request\n return self._endpoint.make_request(operation_model, request_dict)\n", " File \"/var/runtime/botocore/endpoint.py\", line 102, in make_request\n return self._send_request(request_dict, operation_model)\n", " File \"/var/runtime/botocore/endpoint.py\", line 137, in _send_request\n success_response, exception):\n", " File \"/var/runtime/botocore/endpoint.py\", line 256, in _needs_retry\n caught_exception=caught_exception, request_dict=request_dict)\n", " File \"/var/runtime/botocore/hooks.py\", line 356, in emit\n return self._emitter.emit(aliased_event_name, **kwargs)\n", " File \"/var/runtime/botocore/hooks.py\", line 228, in emit\n return self._emit(event_name, kwargs)\n", " File \"/var/runtime/botocore/hooks.py\", line 211, in _emit\n response = handler(**kwargs)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 183, in __call__\n if self._checker(attempts, response, caught_exception):\n", " File \"/var/runtime/botocore/retryhandler.py\", line 251, in __call__\n caught_exception)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 277, in _should_retry\n return self._checker(attempt_number, response, caught_exception)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 317, in __call__\n caught_exception)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 223, in __call__\n attempt_number, caught_exception)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 359, in _check_caught_exception\n raise caught_exception\n", " File \"/var/runtime/botocore/endpoint.py\", line 200, in _do_get_response\n http_response = self._send(request)\n", " File \"/var/runtime/botocore/endpoint.py\", line 269, in _send\n return self.http_session.send(request)\n", " File \"/var/runtime/botocore/httpsession.py\", line 281, in send\n raise SSLError(endpoint_url=request.url, error=e)\n" ] }
原因
どうも最新のcertifi==2020.12.5
だとダメらしい。
応急処置
certifi==2020.11.8
だと動くことを確認したので、Lambda Layerに追加して動くようにします。
なお、今回は手動で更新を行うようにします。
layer.zipの準備
$ mkdir -p layer/python $ cd layler/python $ pip install certifi==2020.11.8 -t . $ cd .. $ zip -r ../layer.zip * $ cd .. $ ls -l layer.zip .rw-r--r-- 158k xxxx 17 Dec 18:46 layer.zip
Layerの作成
左のカラムのレイヤーをクリック。
レイヤーの作成をクリック。
Layerの名前や対象となるランタイムを選択します。
ここでは Python3.6
, Python3.7
, Python3.8
を選択しています。
入力と選択をしたら、作成を押して作成します。
LambdaにLayerを追加する
Layerを追加したいLambda関数の画面に行きます。
デザイナー
をクリックし、開きます。
Lambdaのアイコンと関数名の下のLayers
をクリックして、レイヤー情報を開きます。
そして、レイヤーの追加
をクリックします。
レイヤーを追加の画面に行くので、カスタムレイヤーを選んで先程作成した certifi_layer
のバージョン 1
を選択します。
選択したら、右下の追加
をクリックして追加します。
Layerの追加が行われ、Layersの右に (1)
と表示されます。
これで応急処置は完了です。
Lambdaを動かしてみる
import json import boto3 iot = boto3.client('iot-data') def lambda_handler(event, context): # TODO implement resp = iot.get_thing_shadow(thingName='lip_t9999') return resp['payload'].read().decode()
Layer追加前
Layer追加後
まとめ
応急処置としてLayerを追加することでGetThingShadowできるようになります。
急にSSLエラーが出て困ってる人の役に立てたら幸いです。